package org.legzo.castorranker.ranker;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Game implements Comparable<Game>, Serializable {
	private static final long serialVersionUID = 8893871459580943473L;

	// key: joueurs à cette partie, value: score à cette partie
	private Map<Player, Integer> players = new HashMap<Player, Integer>();
	private boolean ranked = false;
	private Date date;

	public Game(Date date) {
		this.date = date;
	}

	public Map<Player, Integer> getScores() {
		return players;
	}

	public void rankPlayers() {
		if (ranked)
			return;

		Logger logger = LoggerFactory.getLogger(Game.class);

		// sorting all players
		List<Player> sPlayers = new ArrayList<Player>(players.keySet());
		Collections.sort(sPlayers, new Comparator<Player>() {
			public int compare(Player o1, Player o2) {
				return players.get(o2).compareTo(players.get(o1));
			}
		});

		int currentIndex = -1;
		for (Player player : sPlayers) {
			currentIndex++;

			logger.trace("{} - {} ({})", new Object[] { currentIndex + 1, player.getName(), players.get(player) });

			int oCurIndex = -1;
			for (Player otherPlayer : sPlayers) {
				oCurIndex++;
				if (oCurIndex > currentIndex) {
					if (players.get(player) > players.get(otherPlayer)) {
						logger.trace("{} beats {}", player.getName(), otherPlayer.getName());
						player.beats(this, otherPlayer, players.get(player) - players.get(otherPlayer));
					} else {
						logger.trace("{} ties {}", player.getName(), otherPlayer.getName());
						player.ties(this, otherPlayer);
					}
				}
			}
		}
		ranked = true;
	}

	public void addPlayer(Player player, int score) {
		if (isRanked())
			throw new RuntimeException("addPlayer must be called before rank");

		if (score > 0) {
			players.put(player, score);
		}
	}

	public boolean isRanked() {
		return ranked;
	}

	public void displayResults() {
		Logger logger = LoggerFactory.getLogger(Game.class);
		logger.info("======================");
		if (ranked) {
			for (Player player : players.keySet()) {
				logger.info("{}: {}", player.getName(), player.getRanking());
			}
		} else {
			logger.error("Game has not been ranked yet");
		}
	}

	public Date getDate() {
		return date;
	}

	public int compareTo(Game o) {
		return this.date.compareTo(o.getDate());
	}

	@Override
	public String toString() {
		return "Game [date=" + date + "]";
	}

}
